const fs = require('fs');
const path = require('path');
const babylon = require('babylon');
const traverse = require('babel-traverse').default;
const babel = require('babel-core');

let ID = 0;

function createAsset(filename) {
    const content = fs.readFileSync(filename, 'utf-8');

    // 转换为AST
    const ast = babylon.parse(content, {
        sourceType: 'module'
    });

    const dependencies = [];

    // 找到import依赖
    traverse(ast, {
        ImportDeclaration: ({
            node
        }) => {
            dependencies.push(node.source.value);
        }
    })

    const id = ID++;

    // es6转换为es5
    const {
        code
    } = babel.transformFromAst(ast, null, {
        // 告诉babel以什么方式编译我们的代码
        presets: ['env']
    })

    return {
        id,
        filename,
        dependencies,
        code
    }
}

function createGraph(entry) {
    const mainAsset = createAsset(entry);
    const allAsset = [mainAsset];

    console.log(mainAsset,8665);

    for (let asset of allAsset) {
        const dirname = path.dirname(asset.filename);

        asset.mapping = {};

        asset.dependencies.forEach(relativePath => {
            const absoultePath = path.join(dirname, relativePath);
            // 找到相对于项目等路径 例如 const graph = createGraph('./source/entry.js'); 
            // 将./message 变为 ./source/message.js
            const childAsset = createAsset(absoultePath);

            asset.mapping[relativePath] = childAsset.id;

            allAsset.push(childAsset);
        });
    }

    return allAsset;
}

function bundle(graph) {
    let modules = '';

    graph.forEach(module => {
        modules += `${module.id}:[
            function(require, module, exports) {
                ${module.code}
            },
            ${JSON.stringify(module.mapping)},
        ],`;
    })

    const result = `
        (function(modules) {
            function require(id) {
                const [fn, mapping] = modules[id];

                function localRequire(relativePath) {
                    return require(mapping[relativePath]);
                }

                const module = { exports: {}};

                fn(localRequire, module, module.exports);

                return module.exports;
            }
            require(0);
        })({${modules}})
    `;

    return result;
}

const graph = createGraph('./source/entry.js');
console.log(graph,233);
const result = bundle(graph)
console.log(result);

/**
 * graph
 * [
  {
    id: 0,
    filename: './source/entry.js',
    dependencies: [ './message.js' ],
    code: '"use strict";\n' +
      '\n' +
      'var _message = require("./message.js");\n' +
      '\n' +
      'var _message2 = _interopRequireDefault(_message);\n' +
      '\n' +
      'function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n' +
      '\n' +
      'console.log(_message2.default);',
    mapping: { './message.js': 1 }
  },
  {
    id: 1,
    filename: 'source/message.js',
    dependencies: [ './name.js' ],
    code: '"use strict";\n' +
      '\n' +
      'Object.defineProperty(exports, "__esModule", {\n' +
      '  value: true\n' +
      '});\n' +
      '\n' +
      'var _name = require("./name.js");\n' +
      '\n' +
      'exports.default = _name.name + " is a boy";',
    mapping: { './name.js': 2 }
  },
  {
    id: 2,
    filename: 'source/name.js',
    dependencies: [],
    code: '"use strict";\n' +
      '\n' +
      'Object.defineProperty(exports, "__esModule", {\n' +
      '  value: true\n' +
      '});\n' +
      "var name = exports.name = 'lubai';",
    mapping: {}
  }
] 
 */